package com.afu.demo;


import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 基于JAVA集合的分页包装工具类
 * 仅推荐在数据量不大且存在特殊数据过滤的前提下使用,日常推荐使用基于SQL的分页
 *
 * @author ChenBiHui
 * @date 2023/03/25
 */
public class PageWrapperUtil {

    /**
     * 重载方法,默认使用第一种功能边界方案
     *
     * @param pageEntity 分页实体
     * @param record     待分页集合
     * @param <T>        分页实体/待分页集合所持有的实体数据
     * @return 处理完毕的分页实体 - pageEntity
     */
    public static <T> PageEntity<T> achievePage(PageEntity<T> pageEntity, List<T> record) {
        return PageWrapperUtil.achievePage(pageEntity, record, true);
    }

    /**
     * 实现分页包装
     *
     * @param pageEntity 分页实体
     * @param record     待分页集合
     * @param scheme     功能边界方案(from≥to时,默认开启-[true]:返回空集合;[false]:展示待分页数据的最后一页数据)
     * @param <T>        分页实体/待分页集合所持有的实体数据
     * @return 处理完毕的分页实体 - pageEntity
     */
    public static <T> PageEntity<T> achievePage(PageEntity<T> pageEntity, List<T> record, boolean scheme) {
        /*
        若当前页为空或小于1,则将当前页固化为:1
         */
        if (Objects.isNull(pageEntity.getCurrent()) || pageEntity.getCurrent().compareTo(1) < 0) {
            pageEntity.setCurrent(1);
        }
        /*
        若每页大小为空或小于1,则将每页大小固化为:10
         */
        if (Objects.isNull(pageEntity.getSize()) || pageEntity.getSize().compareTo(1) < 0) {
            pageEntity.setSize(10);
        }
        /*
        若传入的待包装集合为空或大小为0,则填充相关信息后,直接返回分页实体
         */
        if (Objects.isNull(record) || record.isEmpty()) {
            pageEntity.setCurrent(1);
            pageEntity.setTotal(0);
            pageEntity.setPageTotal(0);
            pageEntity.setRecord(Objects.isNull(record) ? new ArrayList<>() : record);
            return pageEntity;
        }
        /*
        设置总数
         */
        pageEntity.setTotal(record.size());
        /*
        设置总页数(数据总数若能整除每页大小,直接沿用其商值,否则在商值的基础上+1,保证总页数能承载数据总数的分区)
         */
        pageEntity.setPageTotal(pageEntity.getTotal() % pageEntity.getSize() == 0 ?
                pageEntity.getTotal() / pageEntity.getSize() :
                pageEntity.getTotal() / pageEntity.getSize() + 1);
        /*
        设置截取起始值(基于集合截取方法的基0位为始进行算法处理,即:每页大小*(当前页-1);如:每页大小为5,当前页2,则从集合元素下标[5](即第6位)开始截取)
         */
        int from = pageEntity.getSize() * (pageEntity.getCurrent() - 1);
        /*
        设置截取终点值(基于集合截取方法的开区间为终进行算法处理,
        即:每页大小+起始值;如:每页大小为5,起始值为5,和为10,则在集合元素遍历到下标[10](即第11位)之前则结束截取,只截取到[9]),
        同时进行最小值判断,规避集合越界
         */
        int to = Math.min(pageEntity.getSize() + from, pageEntity.getTotal());
        /*
        功能边界选择核心逻辑:提供两种选择,可自行选择不同的功能边界逻辑;默认开启第一种
        第一种:
        当from大于等于to时,使截取起始与终点永远一致,即永远截空值
        (截取起始与终点相等时,由于底层是一个SubList,最终会使得SubList的size属性为0,
        由于size已经为0,即不再对原集合进行偏移量的计算和填充,所以截取返回的永远是一个空集合;
        注意:起始与终点相等的最大边界为该集合的size值,否则会在初始化SubList前抛出下标越界的异常)
        第二种:
        当from大于等于to时,规避集合截取悖论与越界,即:从[12]截取到[10]的不可能发生事件
        因终点值to受到最小值判断的影响,当出现from大于等于to的情况时,则让起始值永远置于最后一页的数据;
         */
        if (from >= to) {
            if (scheme) {
                from = to;
            } else {
                from = pageEntity.getSize() * (pageEntity.getPageTotal() - 1);
                pageEntity.setCurrent(pageEntity.getPageTotal());
            }
        }
        /*
        边界完善后,进行数据截取,并将截取后的数据进行填充
         */
        pageEntity.setRecord(record.subList(from, to));
        return pageEntity;
    }
}
